#define INSWORD (ctx->insword)
#define UNDEFINED { return DECODE_STATUS_UNDEFINED; }
#define UNMATCHED { return DECODE_STATUS_UNMATCHED; }
#define RESERVED(X) { return DECODE_STATUS_RESERVED; }
#define UNALLOCATED(X) {dec->encoding = (X); return DECODE_STATUS_UNALLOCATED; }
#define ENDOFINSTRUCTION { return DECODE_STATUS_END_OF_INSTRUCTION; }
#define SEE { return DECODE_STATUS_LOST; }
#define UNREACHABLE { return DECODE_STATUS_UNREACHABLE; }
/* do NOT return immediately! post-decode pcode might still need to run */ 
#define OK(X) {instr->encoding = (X); instr->operation = enc_to_oper(X); rc = DECODE_STATUS_OK; }
#define assert(X) if(!(X)) { return DECODE_STATUS_ASSERT_FAILED; }

#define BITMASK(N) (((uint64_t)1<<(N))-1)
#define SLICE(X,MSB,LSB) (((X)>>(LSB)) & BITMASK((MSB)-(LSB)+1)) /* get bits [MSB,LSB] */
#define CONCAT(A,B,B_WIDTH) (((A)<<(B_WIDTH))|(B))
#define NOT(X,X_WIDTH) ((X) ^ BITMASK(X_WIDTH))

#define DecodeBitMasksCheckUndefined(N,imms) if((N==0 && (imms==0x3D || imms==0x3B || imms==0x37 || imms==0x2F || imms==0x1F)) || (N==1 && imms==0x3F)) { return DECODE_STATUS_UNDEFINED; }

#define UINT(x) (unsigned int)(x)
#define SInt(X,X_WIDTH) SignExtend((X),(X_WIDTH))
#define INT(x) (signed int)(x)
#define ZeroExtend(X,Y) (uint64_t)(X)
#define LSL(X,Y) ((X)<<(Y))

#define LOG2_TAG_GRANULE 4
#define TAG_GRANULE (1<<LOG2_TAG_GRANULE)

/* pcode -> cpp booleans */
#define TRUE true
#define FALSE false

/* these calls just check generated per-iform boolean variables */
#define EncodingLabeled32Bit() (encoding32)
#define EncodingLabeled64Bit() (encoding64)

// 30 HasXXX() functions used by decode:
#define HasBF16() (ctx->features0 & ARCH_FEATURE_BF16)
#define HasBTI() (ctx->features0 & ARCH_FEATURE_BTI)
#define HasDGH() (ctx->features0 & ARCH_FEATURE_DGH)
#define HasDotProd() (ctx->features0 & ARCH_FEATURE_DotProd)
#define HasFCMA() (ctx->features0 & ARCH_FEATURE_FCMA)
#define HasFHM() (ctx->features0 & ARCH_FEATURE_FHM)
#define HasFP16() (ctx->features0 & ARCH_FEATURE_FP16)
#define HasFRINTTS() (ctx->features0 & ARCH_FEATURE_FRINTTS)
#define HasFlagM() (ctx->features0 & ARCH_FEATURE_FlagM)
#define HasFlagM2() (ctx->features0 & ARCH_FEATURE_FlagM2)
#define HasI8MM() (ctx->features0 & ARCH_FEATURE_I8MM)
#define HasJSCVT() (ctx->features0 & ARCH_FEATURE_JSCVT)
#define HasLOR() (ctx->features0 & ARCH_FEATURE_LOR)
#define HasLRCPC() (ctx->features0 & ARCH_FEATURE_LRCPC)
#define HasLRCPC2() (ctx->features0 & ARCH_FEATURE_LRCPC2)
#define HasLS64() (ctx->features0 & ARCH_FEATURE_LS64)
#define HasLS64_V() (ctx->features0 & ARCH_FEATURE_LS64_V)
#define HasLSE() (ctx->features0 & ARCH_FEATURE_LSE)
#define HasMTE() (ctx->features0 & ARCH_FEATURE_MTE)
#define HasMTE2() (ctx->features0 & ARCH_FEATURE_MTE2)
#define HasPAuth() (ctx->features0 & ARCH_FEATURE_PAuth)
#define HasRAS() (ctx->features0 & ARCH_FEATURE_RAS)
#define HasRDM() (ctx->features0 & ARCH_FEATURE_RDM)
#define HasSHA3() (ctx->features0 & ARCH_FEATURE_SHA3)
#define HasSHA512() (ctx->features0 & ARCH_FEATURE_SHA512)
#define HasSM3() (ctx->features0 & ARCH_FEATURE_SM3)
#define HasSM4() (ctx->features0 & ARCH_FEATURE_SM4)
#define HasSPE() (ctx->features0 & ARCH_FEATURE_SPE)
#define HasTRF() (ctx->features0 & ARCH_FEATURE_TRF)
#define HasWFxT() (ctx->features0 & ARCH_FEATURE_WFxT)
#define HasXS() (ctx->features0 & ARCH_FEATURE_XS)

// 39 HaveXXX() functions used by pcode:
#define HaveAESExt() (ctx->features1 & ARCH_FEATURE_AESExt)
#define HaveAtomicExt() (ctx->features1 & ARCH_FEATURE_AtomicExt)
#define HaveBF16Ext() (ctx->features1 & ARCH_FEATURE_BF16Ext)
#define HaveBTIExt() (ctx->features1 & ARCH_FEATURE_BTIExt)
#define HaveBit128PMULLExt() (ctx->features1 & ARCH_FEATURE_Bit128PMULLExt)
#define HaveCRCExt() (ctx->features1 & ARCH_FEATURE_CRCExt)
#define HaveDGHExt() (ctx->features1 & ARCH_FEATURE_DGHExt)
#define HaveDITExt() (ctx->features1 & ARCH_FEATURE_DITExt)
#define HaveDOTPExt() (ctx->features1 & ARCH_FEATURE_DOTPExt)
#define HaveFCADDExt() (ctx->features1 & ARCH_FEATURE_FCADDExt)
#define HaveFJCVTZSExt() (ctx->features1 & ARCH_FEATURE_FJCVTZSExt)
#define HaveFP16Ext() (ctx->features1 & ARCH_FEATURE_FP16Ext)
#define HaveFP16MulNoRoundingToFP32Ext() (ctx->features1 & ARCH_FEATURE_FP16MulNoRoundingToFP32Ext)
#define HaveFeatLS64() (ctx->features1 & ARCH_FEATURE_FeatLS64)
#define HaveFeatWFxT() (ctx->features1 & ARCH_FEATURE_FeatWFxT)
#define HaveFlagFormatExt() (ctx->features1 & ARCH_FEATURE_FlagFormatExt)
#define HaveFlagManipulateExt() (ctx->features1 & ARCH_FEATURE_FlagManipulateExt)
#define HaveFrintExt() (ctx->features1 & ARCH_FEATURE_FrintExt)
#define HaveInt8MatMulExt() (ctx->features1 & ARCH_FEATURE_Int8MatMulExt)
#define HaveMTE2Ext() (ctx->features1 & ARCH_FEATURE_MTE2Ext)
#define HaveMTEExt() (ctx->features1 & ARCH_FEATURE_MTEExt)
#define HaveNVExt() (ctx->features1 & ARCH_FEATURE_NVExt)
#define HavePACExt() (ctx->features1 & ARCH_FEATURE_PACExt)
#define HavePANExt() (ctx->features1 & ARCH_FEATURE_PANExt)
#define HaveQRDMLAHExt() (ctx->features1 & ARCH_FEATURE_QRDMLAHExt)
#define HaveRASExt() (ctx->features1 & ARCH_FEATURE_RASExt)
#define HaveSBExt() (ctx->features1 & ARCH_FEATURE_SBExt)
#define HaveSHA1Ext() (ctx->features1 & ARCH_FEATURE_SHA1Ext)
#define HaveSHA256Ext() (ctx->features1 & ARCH_FEATURE_SHA256Ext)
#define HaveSHA3Ext() (ctx->features1 & ARCH_FEATURE_SHA3Ext)
#define HaveSHA512Ext() (ctx->features1 & ARCH_FEATURE_SHA512Ext)
#define HaveSM3Ext() (ctx->features1 & ARCH_FEATURE_SM3Ext)
#define HaveSM4Ext() (ctx->features1 & ARCH_FEATURE_SM4Ext)
#define HaveSSBSExt() (ctx->features1 & ARCH_FEATURE_SSBSExt)
#define HaveSVE() (ctx->features1 & ARCH_FEATURE_SVE)
#define HaveSelfHostedTrace() (ctx->features1 & ARCH_FEATURE_SelfHostedTrace)
#define HaveStatisticalProfiling() (ctx->features1 & ARCH_FEATURE_StatisticalProfiling)
#define HaveUAOExt() (ctx->features1 & ARCH_FEATURE_UAOExt)
#define HaveVirtHostExt() (ctx->features1 & ARCH_FEATURE_VirtHostExt)
#define HaveSVEFP32MatMulExt() (ctx->features1 & ARCH_FEATURE_SVEFP32MatMulExt)
#define HaveSVEFP64MatMulExt() (ctx->features1 & ARCH_FEATURE_SVEFP64MatMulExt)
#define HaveFeatXS() (ctx->features1 & ARCH_FEATURE_FeatXS)

// extras we find in spec tables, etc.
#define HaveTLBIOS() (1)
#define HaveTLBIRANGE() (1)
#define HaveDCCVADP() (1)
#define HaveDCPoP() (1)

#define SetBTypeCompatible(X) ctx->BTypeCompatible = (X)
#define SetBTypeNext(X) ctx->BTypeNext = (X)
#define Halted() ctx->halted

enum SystemOp {
	Sys_ERROR=-1,
	Sys_AT=0,
	Sys_DC=1,
	Sys_IC=2,
	Sys_TLBI=3,
	Sys_SYS=4,
};

enum ReduceOp {
	ReduceOp_ERROR=0,
	ReduceOp_ADD,
	ReduceOp_FADD,
	ReduceOp_FMIN,
	ReduceOp_FMAX,
	ReduceOp_FMINNUM,
	ReduceOp_FMAXNUM,
};

enum LogicalOp {
	LogicalOp_ERROR=0,
	LogicalOp_AND,
	LogicalOp_EOR,
	LogicalOp_ORR
};

enum BranchType {
	BranchType_ERROR=0,
	BranchType_DIRCALL,	 // Direct Branch with link
	BranchType_INDCALL,	 // Indirect Branch with link
	BranchType_ERET,		// Exception return (indirect)
	BranchType_DBGEXIT,	 // Exit from Debug state
	BranchType_RET,		 // Indirect branch with function return hint
	BranchType_DIR,		 // Direct branch
	BranchType_INDIR,	   // Indirect branch
	BranchType_EXCEPTION,   // Exception entry
	BranchType_RESET,	   // Reset
	BranchType_UNKNOWN	// Other
};

enum VBitOp {
	VBitOp_ERROR=0,
	VBitOp_VBIF,
	VBitOp_VBIT,
	VBitOp_VBSL,
	VBitOp_VEOR
};

enum SystemHintOp {
	SystemHintOp_ERROR=0,
	SystemHintOp_NOP,
	SystemHintOp_YIELD,
	SystemHintOp_WFE,
	SystemHintOp_WFI,
	SystemHintOp_SEV,
	SystemHintOp_SEVL,
	SystemHintOp_DGH,
	SystemHintOp_ESB,
	SystemHintOp_PSB,
	SystemHintOp_TSB,
	SystemHintOp_BTI,
	SystemHintOp_CSDB,
	SystemHintOp_WFET,
	SystemHintOp_WFIT,
};

enum ImmediateOp {
	ImmediateOp_ERROR=0,
	ImmediateOp_MOVI,
	ImmediateOp_MVNI,
	ImmediateOp_ORR,
	ImmediateOp_BIC
};

enum AccType {
	AccType_ERROR=0,
	AccType_ATOMICRW,
	AccType_ATOMIC,
	AccType_LIMITEDORDERED,
	AccType_ORDEREDATOMICRW,
	AccType_ORDEREDATOMIC,
	AccType_ORDERED
};

enum CompareOp {
	CompareOp_ERROR=0,
	CompareOp_EQ,
	CompareOp_GE,
	CompareOp_GT,
	CompareOp_LE,
	CompareOp_LT
};

enum Constraint {
	Constraint_ERROR=0,
	Constraint_DISABLED,
	Constraint_FALSE,
	Constraint_FAULT,
	Constraint_FORCE,
	Constraint_LIMITED_ATOMICITY,
	Constraint_NONE,
	Constraint_NOP,
	Constraint_TRUE,
	Constraint_UNDEF,
	Constraint_UNKNOWN,
	Constraint_WBSUPPRESS,
};

enum CountOp {
	CountOp_ERROR=0,
	CountOp_CLS,
	CountOp_CLZ
};

enum MBReqDomain {
	MBReqDomain_ERROR=0,
	MBReqDomain_Nonshareable,
	MBReqDomain_InnerShareable,
	MBReqDomain_OuterShareable,
	MBReqDomain_FullSystem
};

enum MBReqTypes {
	MBReqTypes_ERROR=0,
	MBReqTypes_Reads,
	MBReqTypes_Writes,
	MBReqTypes_All
};

enum FPUnaryOp {
	FPUnaryOp_ERROR=0,
	FPUnaryOp_ABS,
	FPUnaryOp_MOV,
	FPUnaryOp_NEG,
	FPUnaryOp_SQRT
};

enum FPConvOp {
	FPConvOp_ERROR=0,
	FPConvOp_CVT_FtoI,
	FPConvOp_CVT_ItoF,
	FPConvOp_MOV_FtoI,
	FPConvOp_MOV_ItoF,
	FPConvOp_CVT_FtoI_JS
};

enum FPMaxMinOp {
	FPMaxMinOp_ERROR=0,
	FPMaxMinOp_MAX,
	FPMaxMinOp_MIN,
	FPMaxMinOp_MAXNUM,
	FPMaxMinOp_MINNUM
};

enum FPRounding {
	FPRounding_ERROR=0,
	FPRounding_TIEEVEN,
	FPRounding_POSINF,
	FPRounding_NEGINF,
	FPRounding_ZERO,
	FPRounding_TIEAWAY,
	FPRounding_ODD
};

enum MemAtomicOp {
	MemAtomicOp_ERROR=0,
	MemAtomicOp_ADD,
	MemAtomicOp_BIC,
	MemAtomicOp_EOR,
	MemAtomicOp_ORR,
	MemAtomicOp_SMAX,
	MemAtomicOp_SMIN,
	MemAtomicOp_UMAX,
	MemAtomicOp_UMIN,
	MemAtomicOp_SWP
};

enum MemOp {
	MemOp_ERROR=0,
	MemOp_LOAD,
	MemOp_STORE,
	MemOp_PREFETCH
};

enum MoveWideOp {
	MoveWideOp_ERROR=0,
	MoveWideOp_N,
	MoveWideOp_Z,
	MoveWideOp_K
};

enum PSTATEField {
	PSTATEField_ERROR=0,
	PSTATEField_DAIFSet,
	PSTATEField_DAIFClr,
	PSTATEField_PAN, // Armv8.1
	PSTATEField_UAO, // Armv8.2
	PSTATEField_DIT, // Armv8.4
	PSTATEField_SSBS,
	PSTATEField_TCO, // Armv8.5
	PSTATEField_SP
};

enum SVECmp {
	Cmp_ERROR=-1,
	Cmp_EQ,
	Cmp_NE,
	Cmp_GE,
	Cmp_GT,
	Cmp_LT,
	Cmp_LE,
	Cmp_UN
};

enum PrefetchHint {
	Prefetch_ERROR=-1,
	Prefetch_READ,
	Prefetch_WRITE,
	Prefetch_EXEC
};

enum Unpredictable {
	Unpredictable_ERROR=-1,
	Unpredictable_VMSR,
	Unpredictable_WBOVERLAPLD,
	Unpredictable_WBOVERLAPST,
	Unpredictable_LDPOVERLAP,
	Unpredictable_BASEOVERLAP,
	Unpredictable_DATAOVERLAP,
	Unpredictable_DEVPAGE2,
	Unpredictable_DEVICETAGSTORE,
	Unpredictable_INSTRDEVICE,
	Unpredictable_RESCPACR,
	Unpredictable_RESMAIR,
	Unpredictable_RESTEXCB,
	Unpredictable_RESDACR,
	Unpredictable_RESPRRR,
	Unpredictable_RESVTCRS,
	Unpredictable_RESTnSZ,
	Unpredictable_OORTnSZ,
	Unpredictable_LARGEIPA,
	Unpredictable_ESRCONDPASS,
	Unpredictable_ILZEROIT,
	Unpredictable_ILZEROT,
	Unpredictable_BPVECTORCATCHPRI,
	Unpredictable_VCMATCHHALF,
	Unpredictable_VCMATCHDAPA,
	Unpredictable_WPMASKANDBAS,
	Unpredictable_WPBASCONTIGUOUS,
	Unpredictable_RESWPMASK,
	Unpredictable_WPMASKEDBITS,
	Unpredictable_RESBPWPCTRL,
	Unpredictable_BPNOTIMPL,
	Unpredictable_RESBPTYPE,
	Unpredictable_BPNOTCTXCMP,
	Unpredictable_BPMATCHHALF,
	Unpredictable_BPMISMATCHHALF,
	Unpredictable_RESTARTALIGNPC,
	Unpredictable_RESTARTZEROUPPERPC,
	Unpredictable_ZEROUPPER,
	Unpredictable_ERETZEROUPPERPC,
	Unpredictable_A32FORCEALIGNPC,
	Unpredictable_SMD,
	Unpredictable_NONFAULT,
	Unpredictable_SVEZEROUPPER,
	Unpredictable_SVELDNFDATA,
	Unpredictable_SVELDNFZERO,
	Unpredictable_CHECKSPNONEACTIVE,
	Unpredictable_AFUPDATE,     // AF update for alignment or permission fault,
	Unpredictable_IESBinDebug,  // Use SCTLR[].IESB in Debug state,
	Unpredictable_BADPMSFCR,    // Bad settings for PMSFCR_EL1/PMSEVFR_EL1/PMSLATFR_EL1,
	Unpredictable_ZEROBTYPE,
	Unpredictable_CLEARERRITEZERO, // Clearing sticky errors when instruction in flight,
	Unpredictable_ALUEXCEPTIONRETURN,
	Unpredictable_DBGxVR_RESS,
	Unpredictable_WFxTDEBUG,
	Unpredictable_LS64UNSUPPORTED,
};

typedef struct DecodeBitMasks_ReturnType_ {
	uint64_t wmask;
	uint64_t tmask;
} DecodeBitMasks_ReturnType;

int HighestSetBit(uint64_t x);
int LowestSetBit(uint64_t x);

bool BFXPreferred(uint32_t sf, uint32_t uns, uint32_t imms, uint32_t immr);
int BitCount(uint32_t x);
DecodeBitMasks_ReturnType DecodeBitMasks(uint8_t /*bit*/ immN, uint8_t /*bit(6)*/ imms, uint8_t /*bit(6)*/ immr);

enum Constraint ConstrainUnpredictable(enum Unpredictable);
bool MoveWidePreferred(uint32_t sf, uint32_t immN, uint32_t imms, uint32_t immr);
bool SVEMoveMaskPreferred(uint32_t imm13);
enum ShiftType DecodeRegExtend(uint8_t op);
enum ShiftType DecodeShift(uint8_t op);
enum SystemOp SysOp(uint32_t op1, uint32_t CRn, uint32_t CRm, uint32_t op2);
uint32_t UInt(uint32_t);
uint32_t BitSlice(uint64_t, int hi, int lo); // including the endpoints
bool IsZero(uint64_t foo);
bool IsOnes(uint64_t foo, int width);
uint64_t Replicate(uint64_t val, uint8_t times, uint64_t width);
uint64_t AdvSIMDExpandImm(uint8_t op, uint8_t cmode, uint64_t imm8);

bool BTypeCompatible_BTI(uint8_t hintcode, uint8_t pstate_btype);
bool BTypeCompatible_PACIXSP(void);

enum FPRounding FPDecodeRounding(uint8_t RMode);
enum FPRounding FPRoundingMode(uint64_t fpcr);

bool HaltingAllowed(void);
void SystemAccessTrap(uint32_t a, uint32_t b);
void CheckSystemAccess(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);

uint64_t VFPExpandImm(uint8_t imm8, unsigned width);

#define EL0 0
#define EL1 1
#define EL2 2
#define EL3 3
bool EL2Enabled(void);
bool ELUsingAArch32(uint8_t);

uint64_t FPOne(bool sign, int width);
uint64_t FPTwo(bool sign, int width);
uint64_t FPPointFive(bool sign, int width);

uint64_t SignExtend(uint64_t x, int width);
